/* Syntax Highlighter 1.0
 * Made by Michiel van Eerd, 2007
 * http://www.webessence.nl
 */

var Language = function() {

}

var Highlighter = function(withLineNumbers) {
	this.withLineNumbers = withLineNumbers;
	this.words = new Array("keyword", "function");
}

/* IE doesn't understand indexOf() on arrays, so add it */
if (!Array.prototype.indexOf) {
        Array.prototype.indexOf = function(val) {
                var len = this.length;
                for (var i = 0; i < len; i++) {
                        if (this[i] == val) return i;
                }
                return -1;
        }
}

Highlighter.prototype.init = function() {

	var lang = new Language();

	var codes = document.getElementsByTagName("code");
	for (var i = 0, codesLen = codes.length; i < codesLen; i++) {
		if (codes[i].className != "" && lang[codes[i].className]) {
			this.highlight(codes[i], lang[codes[i].className]);
		}
	}

}

Highlighter.prototype.highlight = function(codeEl, ob) {

	var str = "";
	var lines;
	for (var i = 0; i < codeEl.childNodes.length; i++) {
		str += codeEl.childNodes[i].data;
	}
	lines = str.split("\n");
	if (lines.length == 1) lines = str.split("\r");
	var linesLen = lines.length;
	
	var hasDoubleComment = false; // stores if at the beginning of this line, we are inside a double comment
	
	forLineLoop:
	for (var lineIndex = 0, linesLen = lines.length; lineIndex < linesLen; lineIndex++) {

		var line = lines[lineIndex];
		var prop = new Object();
		
		// Singlecomments are handled when they are processed (because until end of line...)
		
		forCharLoop:
		for (var charIndex = 0, lineLen = line.length; charIndex < lineLen; charIndex++) {
		
			var c = line.charAt(charIndex);
			
			if (hasDoubleComment) {
				
				var endDoubleComment = false;
				var beginDoubleCommentIndex = charIndex;
				var i;
				for (charIndex = 0; charIndex < lineLen; charIndex++) {
					if (line.charAt(charIndex) == ob.comment.double.end.charAt(0)) {
						endDoubleComment = true;
						for (i = 1; i < ob.comment.double.end.length; i++) {
							if (line.charAt(charIndex + i) != ob.comment.double.end.charAt(i)) {
								endDoubleComment = false;
								break;
							}
						}
						if (endDoubleComment) {
							hasDoubleComment = false;
							var substrLen = charIndex + i - beginDoubleCommentIndex;
							var substr = line.substr(beginDoubleCommentIndex, substrLen);
							var replaces = 0;
							substr = substr.replace(/</g,
								function(m, offset, s) {
									replaces += 1;
									return "&lt;";
								}
							);
							line = line.substr(0, beginDoubleCommentIndex) + "<span class=\"comment\">" + substr + "</span>" + line.substr(charIndex + i);
							prop[beginDoubleCommentIndex] = substrLen + "<span class=\"comment\"></span>".length + replaces * 3;
							charIndex += i + "<span class=\"comment\"></span>".length + replaces * 3;
							lineLen += "<span class=\"comment\"></span>".length + replaces * 3;
							continue forCharLoop;
						}
					}
				}
				if (!endDoubleComment) {
					hasDoubleComment = true;
					var substr = line.substr(beginDoubleCommentIndex);
					var replaces = 0;
					substr = substr.replace(/</g,
						function(m, offset, s) {
							replaces += 1;
							return "&lt;";
						}
					);
					line = line.substr(0, beginDoubleCommentIndex) + "<span class=\"comment\">" + substr + "</span>";
					lineLen += "<span class=\"comment\"></span>".length + replaces * 3;
					prop[beginDoubleCommentIndex] = lineLen - beginDoubleCommentIndex + 1;
					charIndex = lineLen;
					continue forCharLoop;
				}
						
			}
			
			if (ob.comment.single && c == ob.comment.single.begin.charAt(0)) {
				var singleComment = true;
				for (var i = 1; i < ob.comment.single.begin.length; i++) {
					if (line.charAt(charIndex + i) != ob.comment.single.begin.charAt(i)) {
						singleComment = false;
						break;
					}
				}
				if (singleComment) {
					line = line.substr(0, charIndex) + "<span class=\"comment\">" + line.substr(charIndex) + "</span>";
					prop[charIndex] = lineLen - charIndex + "<span class=\"comment\"></span>".length;
					charIndex = lineLen - 1;
					continue forCharLoop;
				}
			}
			
			if (ob.comment.double && c == ob.comment.double.begin.charAt(0)) {
				var beginDoubleComment = true;
				var i;
				for (i = 1; i < ob.comment.double.begin.length; i++) {
					if (line.charAt(charIndex + i) != ob.comment.double.begin.charAt(i)) {
						beginDoubleComment = false;
						break;
					}
				}
				if (beginDoubleComment) {
					var endDoubleComment = false;
					var beginDoubleCommentIndex = charIndex;
					for (charIndex += i; charIndex < lineLen; charIndex++) {
						if (line.charAt(charIndex) == ob.comment.double.end.charAt(0)) {
							endDoubleComment = true;
							for (i = 1; i < ob.comment.double.end.length; i++) {
								if (line.charAt(charIndex + i) != ob.comment.double.end.charAt(i)) {
									endDoubleComment = false;
									break;
								}
							}
							if (endDoubleComment) {
								var substrLen = charIndex + i - beginDoubleCommentIndex;
								var substr = line.substr(beginDoubleCommentIndex, substrLen);
								var replaces = 0;
								substr = substr.replace(/</g,
									function(m, offset, s) {
										replaces += 1;
										return "&lt;";
									}
								);
								line = line.substr(0, beginDoubleCommentIndex) + "<span class=\"comment\">" + substr + "</span>" + line.substr(charIndex + i);
								prop[beginDoubleCommentIndex] = substrLen + "<span class=\"comment\"></span>".length + replaces * 3;
								charIndex += i - 1 + "<span class=\"comment\"></span>".length + replaces * 3;
								lineLen += "<span class=\"comment\"></span>".length + replaces * 3;
								continue forCharLoop;
							}
						}
					}
					if (!endDoubleComment) {
						hasDoubleComment = true;
						var substr = line.substr(beginDoubleCommentIndex);
						var replaces = 0;
						substr = substr.replace(/</g,
							function(m, offset, s) {
								replaces += 1;
								return "&lt;";
							}
						);
						line = line.substr(0, beginDoubleCommentIndex) + "<span class=\"comment\">" + substr + "</span>";
						lineLen += "<span class=\"comment\"></span>".length + replaces * 3;
						prop[beginDoubleCommentIndex] = lineLen - beginDoubleCommentIndex + 1;
						charIndex = lineLen;
						continue forCharLoop;
					}
				}
			}
				
			// quotes?
			for (var i = 0; i < ob.quote.length; i++) {
				if (c == ob.quote[i]) {
					var isEscaped = false;
					for (var j = charIndex + 1; j < lineLen; j++) {
						if (line.charAt(j) == "\\") {
							isEscaped = !isEscaped;
						} else if (line.charAt(j) == c && !isEscaped) {
							var substrLen = j - charIndex + 1;
							var substr = line.substr(charIndex, substrLen);
							var replaces = 0;
							substr = substr.replace(/</g,
								function(m, offset, s) {
									replaces += 1;
									return "&lt;";
								}
							);
							line = line.substr(0, charIndex) + "<span class=\"quote\">" + substr + "</span>" + line.substr(j + 1);
							prop[charIndex] = substrLen + "<span class=\"quote\"></span>".length + replaces * 3;
							charIndex = j + "<span class=\"quote\"></span>".length + replaces * 3;
							lineLen += "<span class=\"quote\"></span>".length + replaces * 3;
							continue forCharLoop;
						} else {
							isEscaped = false;
						}
					}
				}
			}
			
			// signs?
			for (var i = 0; i < ob.sign.length; i++) {
				if (c == ob.sign[i]) {
					var substrLen = "<span class=\"sign\"></span>".length + 1;
					line = line.substr(0, charIndex) + "<span class=\"sign\">" + c + "</span>" + line.substr(charIndex + 1);
					prop[charIndex] = substrLen;
					charIndex += substrLen - 1;
					lineLen += substrLen - 1;
					continue forCharLoop;
				}
			}
					
					
		}
		
		// Nu de keywords en functions
		for (var wordCount = 0; wordCount < this.words.length; wordCount++) {
			var thisword = this.words[wordCount];
			for (var i = 0; i < ob[thisword].length; i++) {
				var keyword = ob[thisword][i];
				var kIndex = line.indexOf(keyword);
				while (kIndex != -1) {
					if (/\w/.test(line.charAt(kIndex - 1)) || /\w/.test(line.charAt(kIndex + keyword.length))) {
						kIndex = line.indexOf(keyword, kIndex + 1);
						continue;
					}
					var isKeyword = true;
					for (var key in prop) {
						if (kIndex >= parseInt(key) && kIndex < (parseInt(key) + parseInt(prop[key]))) {
							isKeyword = false;
							break;
						}
					}
					if (isKeyword) {
						var addString = "<span class=\"" + thisword + "\"></span>";
						var addLen = addString.length; // dit is erbij gekomen
						line = line.substr(0, kIndex) + "<span class=\"" + thisword + "\">" + keyword + "</span>" + line.substr(kIndex + keyword.length);
						prop[kIndex] = keyword.length + addLen;
						var tmpOb = new Object();
						for (var key in prop) {
							if (parseInt(key) > kIndex) {
								var newIndex = parseInt(key) + addLen;
								tmpOb[newIndex] = prop[key];
							} else {
								tmpOb[key] = prop[key];
							}
						}
						prop = this.copyObject(tmpOb);
						kIndex = line.indexOf(keyword, kIndex + addLen + keyword.length);
					} else {
						kIndex = line.indexOf(keyword, kIndex + 1);
					}
				}
			}
		}
		
		// Maybe now language specific routine???
		if (ob.routine) line = ob.routine(line, prop);
		
		lines[lineIndex] = line;
		
	}
	
	var isInline = false;
	var wlinen = this.withLineNumbers;
	if (codeEl.parentNode.nodeName.toLowerCase() != "pre") {
		wlinen = false;
		isInline = true;
	}

	this.printLines(codeEl, lines, linesLen, isInline, wlinen);

}

Highlighter.prototype.copyObject = function (ob) {
	var newOb = new Object();
	for (var prop in ob) {
		newOb[prop] = ob[prop];
	}
	return newOb;
}

// Prints all lines with linenumbers as firstchild of codeEl
Highlighter.prototype.printLines = function(codeEl, lines, linesLen, isInline, wlinen) {

	var newlines;
	var joinString = "";
	
	if (wlinen) {
		codeEl.parentNode.className = "highlight";
		newlines = new Array("<ol>");
		for (var i = 0; i < linesLen; i++) {
			newlines.push("<li><span>" + lines[i] + "</span>&nbsp;</li>");
		}
		newlines.push("</ol>");
	} else {
		newlines = lines;
		if (!isInline) joinString = "\n";
	}

	if (codeEl.outerHTML && !isInline) { // IE doesn't preserve whitespace in innerHTML...this works...
		codeEl.parentNode.outerHTML = "<" + codeEl.parentNode.nodeName + " class=\"highlight\"><code class=\"" + codeEl.className + "\">" + newlines.join(joinString) + "</code></" + codeEl.parentNode.nodeName + ">";
	} else {
		codeEl.innerHTML = newlines.join(joinString);
	}
	
}
